//=================================================
// D_NC_gateway.c
// 2015-02-14
#define NC_VERSION "D_NC_0.1" 
//=================================================
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <termios.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>


//#define MODEM "/dev/ttyACM0"
#define BAUDRATE B9600   
#define NABTON_DATA     1
#define NABTON_DATA_ACK 2
#define NABTON_NODATA   3
#define NABTON_LOG      8
#define NABTON_ERROR    9

// Nabton Control Protocol
#define ON_NABTON_SID    1
#define ON_DELAY         2
#define ON_STEPPER_CTRL  4

// Arduino Control Protocol
#define ON_DELAY_VAL     2
#define ON_DELAY_UNIT    3
#define ON_STEPPER_DIR   4
#define ON_STEPPER_STEPS 5
#define ON_STEPPER_SPEED 6

#define INIT    1
#define RUNNING 2
#define READY   3

struct termios tio;
int  tty_fd, flags;

char res[512];
// Configuration parameters
char arh_url[80];
char arh_page[80];
char arh_dev[80];
char nb_errmsg[120];
int  nb_err = 0;
char nb_logmsg[120];
int  nb_log = 0;
int  nb_sid     = 0;
int  nb_mid;
int  nb_nodata = 0;
int  on[100];
int  value[100];
float nb_data  = 0.0;
int   nb_float = 3;
char  msg[200];
int   silent = 1;
int  g_count = 0;
char g_buf[500];

int create_tcp_socket();
char *get_ip(char *host);
char *build_get_query(char *host, char *page);
void usage();
char* httpClient(char* host, char* page);
 
#define HOST "coding.debuntu.org"
#define PAGE "/"
#define PORT 80
#define USERAGENT "HTMLGET 1.0"
//=================================================
void serialFlush()
//=================================================
{
  char c;
  if(silent==0)printf("\nGWY: flushing:");
  while(read(tty_fd,&c,1)>0) {
   if(silent==0)printf("(%c)",c);
  }
  if(silent==0)printf(":flushed\n");
}   
//===============================
int toString(char a[]) 
//===============================
{
  int c, sign, offset, n;
 
  if (a[0] == '-') {  // Handle negative integers
    sign = -1;
  }
 
  if (sign == -1) {  // Set starting position to convert
    offset = 1;
  }
  else {
    offset = 0;
  }
 
  n = 0;
 
  for (c = offset; a[c] != '\0'; c++) {
    n = n * 10 + a[c] - '0';
  }
 
  if (sign == -1) {
    n = -n;
  }
 
  return n;
}

//===============================
void sendArduino(int n,unsigned char *msg)
//===============================
{
  unsigned char c='D';
  unsigned char z='D';
  int i;

  //serialFlush();
  //for(i=0;i<n;i++)
    //{
      //z = msg[i];
      //if(silent==0)printf("GWY: i=%d send %d %c\n ",i,(int)z,z);
      //write(tty_fd,&z,1);  // Write Serial data to Arduino
    //}
  //tcsetattr(tty_fd, TCSAFLUSH, &tio);
  if(silent==0)printf("sendArduino: %s\n ",msg);
  write(tty_fd,msg,strlen(msg));  // Write Serial data to Arduino
  return;
}

//===============================
int recArduino()
//===============================
{
  unsigned char c='D';
  unsigned char z='D';
  int i,temp1,temp2,checksum;
  unsigned char inres[240];

  printf("b1\n"); 

  int nn = 0;
  while (c != ';')
    {
		  printf("b2\n"); 
      if (read(tty_fd,&c,1)>0) 
        {
			  printf("b3\n"); 
          if(silent==0)printf("<%c>\n",c);
          inres[nn] = c;
          nn++;
        }
    }
      printf("b4\n"); 
  c = ' ';
  inres[nn-1] = '\0';
  printf("b5\n"); 
  if(silent==0)printf("RGWY: Received from Arduino: (%s) len=%d\n",inres,nn);
  nb_mid = 0;
  sscanf(inres,"%d %d %d",&nb_mid,&nb_sid,&checksum);
 
 if(checksum == nb_sid + nb_mid)
 {
  if(nb_mid == NABTON_DATA)
  {
    sscanf(inres,"%d %d %d %f",&nb_mid,&nb_sid,&nb_float,&nb_data);
    if(silent==0)printf("RGWY: DATA mid=%d sid=%d float=%d data=%f\n", nb_mid, nb_sid, nb_float, nb_data);
    nb_nodata = 0;
    return(1);
  }
  else if(nb_mid == NABTON_NODATA)
  {
    sscanf(inres,"%d %d",&nb_mid,&nb_sid);
    if(silent==0)printf("RGWY: NO DATA mid=%d sid=%d\n", nb_mid, nb_sid);
    nb_nodata = 1;
    return(1);
  }
  else if(nb_mid == NABTON_ERROR)
  {
    sscanf(inres,"%d %d %s",&nb_mid,&nb_err,nb_errmsg);
    if(silent==0)printf("RGWY: ERROR mid=%d err=%d msg=%s\n", nb_mid, nb_err, nb_errmsg);
    return(3);
  }
  else if(nb_mid == NABTON_LOG)
  {
    sscanf(inres,"%d %d %s",&nb_mid,&nb_log,nb_logmsg);
    if(silent==0)printf("RGWY: LOG mid=%d log=%d msg=%s\n", nb_mid, nb_log, nb_logmsg);
    return(4);
  }
 }
 else
    return(2);
 
}
//===============================
void delay(int t)
//===============================
{
  t = t*1000; // convert to ms
  usleep(t);
}
//===============================
int split (char *str, char c, char ***arr)
//===============================
{
    int count = 1;
    int token_len = 1;
    int i = 0;
    char *p;
    char *t;

    p = str;
    while (*p != '\0')
    {
        if (*p == c)
            count++;
        p++;
    }

    *arr = (char**) malloc(sizeof(char*) * count);
    if (*arr == NULL)
        exit(1);

    p = str;
    while (*p != '\0')
    {
        if (*p == c)
        {
            (*arr)[i] = (char*) malloc( sizeof(char) * token_len );
            if ((*arr)[i] == NULL)
                exit(1);

            token_len = 0;
            i++;
        }
        p++;
        token_len++;
    }
    (*arr)[i] = (char*) malloc( sizeof(char) * token_len );
    if ((*arr)[i] == NULL)
        exit(1);
   i = 0;
    p = str;
    t = ((*arr)[i]);
    while (*p != '\0')
    {
        if (*p != c && *p != '\0')
        {
            *t = *p;
            t++;
        }
        else
        {
            *t = '\0';
            i++;
            t = ((*arr)[i]);
        }
        p++;
    }

    return count;
}
//===============================
void handleServerResponse(char* ht)
//===============================
{
	char  line[128],key[32];
    int   itemp,k,val1,val2,val3,answer = 0;
    int   i;
    int   c = 0;
    char  **arr = NULL;

    c = split(ht, ':', &arr);

    printf("found %d tokens.\n", c);

    for (i = 0; i < c; i++)
    {
      //printf("string #%d: %s\n", i, arr[i]);
      strcpy(line,arr[i]);
          if(silent==0)printf("%s\n",line);
          sscanf(line,"%s",key);
          if(strstr(key,"NABTON_SID")    != NULL) 
          {
			  sscanf(line,"%s %d",key,&val1);
			  answer = 1; 
			  nb_sid = val1;
		  }
          if(strstr(key,"DELAY")     != NULL) 
          {
			  answer = 1; 
			  sscanf(line,"%s %d %d",key,&val1,&val2);
			  on[ON_DELAY_VAL]  = 1; 
			  on[ON_DELAY_UNIT]  = 1; 
			  value[ON_DELAY_VAL]  = val1;
			  value[ON_DELAY_UNIT] = val2;   
	      }
          if(strstr(key,"STEPPER_CTRL")  != NULL) 
          {
			  answer = 1; 
			  sscanf(line,"%s %d %d %d",key,&val1,&val2,&val3);
			  on[ON_STEPPER_DIR] = 1; 
			  on[ON_STEPPER_STEPS] = 1; 
			  on[ON_STEPPER_SPEED] = 1; 
			  value[ON_STEPPER_DIR] = val1;
			  value[ON_STEPPER_STEPS] = val2;
			  value[ON_STEPPER_SPEED] = val3;
		  }
       }
       //sendArduino(1,"+"); // Confirmation
       if(answer == 1)
       {
		  //serialFlush();
		  if(silent==0)printf("GWY: Server Message sid: %d\n",nb_sid);
          msg[0] = NABTON_DATA_ACK;
          msg[1] = (nb_sid&0xff);
          itemp = nb_sid >> 8;
          msg[2] = (itemp&0xff);
          k = 3;
          for(i=0;i<100;i++)
          {
		      if(on[i] != 0)
		      {
				 if(silent==0)printf("GWY: MSG:%d Value: %d\n",i,value[i]);
			     msg[k] = i;
			     msg[k+1] = value[i];
			     k = k + 2;
		      }
	      }
	      msg[k] = 0;
	      if(silent==0)printf("GWY: Total Message size: %d\n",k);
	      k++;
          sendArduino(k,msg);
       }
       else
        if(silent==0)printf("GWY: No Server Message - check if SID is defined in database\n");
     
}

//===============================
void readConfig()
//===============================
{
  FILE  *in,*out;
  char  line[128];
  char temps[12];

  in = fopen("config.nab","r");
  if(in == NULL)
    {
      strcpy(arh_url,   "213.67.148.190");
      strcpy(arh_page,  "nabton/NDSServer/NDSCollector.php");
      strcpy(arh_dev,   "/dev/ttyACM0");
      
      if(silent==0)printf("Create config file\n");
      out = fopen("config.nab","w");
      fprintf(out,"URL:   %s\n",arh_url);
      fprintf(out,"PAGE:  %s\n",arh_page);
      fclose(out);
    }
  else
    {
      if(silent==0)printf("Open config file\n");
      while (fgets(line,sizeof line,in) != NULL)
          {
            if(strstr(line,"URL:") != NULL)sscanf(line,"%s %s",temps,arh_url);
            if(strstr(line,"PAGE:") != NULL)sscanf(line,"%s %s",temps,arh_page);
          }
      fclose(in);
    } 
}
//===============================
void writeDebug()
//===============================
{
  FILE  *out;
  out = fopen("debug.nab","w");
  fprintf(out,"%d",g_count);
  fclose(out);
}

//===============================
void readDeviceName()
//===============================
{
  FILE  *in,*out;
  int n = 0;
  char  line[128];
  char  temps[12];

  system("ls /dev | grep ACM > device.nab"); 
  in = fopen("device.nab","r");
  if(in == NULL)
    {
      printf("No ACM device information file\n");
    }
  else
    {
      while (fgets(line,sizeof line,in) != NULL)
	{ 
          n++;
	  if(strstr(line,"ttyACM") != NULL)sscanf(line,"%s",temps);
	  strcpy(arh_dev,"/dev/");
	  strcat(arh_dev,temps);
	}
      fclose(in);
    }

  if(n > 1)printf("Multiple ACM devices found - check Arduino connection\n");

  if(n == 0)
  {
  system("ls /dev | grep USB > device.nab"); 
  in = fopen("device.nab","r");
  if(in == NULL)
    {
      printf("No USB device information file\n");
    }
  else
    {
      while (fgets(line,sizeof line,in) != NULL)
	{ 
      n++;
	  if(strstr(line,"ttyUSB") != NULL)sscanf(line,"%s",temps);
	  strcpy(arh_dev,"/dev/");
	  strcat(arh_dev,temps);
	}
      fclose(in);
    }

  if(n > 1)printf("Multiple USB devices found - check Arduino connection\n");
  }

  if(n == 0)
  {
  system("ls /dev | grep lirc > device.nab"); 
  in = fopen("device.nab","r");
  if(in == NULL)
    {
      printf("No lirc device information file\n");
    }
  else
    {
      while (fgets(line,sizeof line,in) != NULL)
	{ 
      n++;
	  if(strstr(line,"lirc") != NULL)sscanf(line,"%s",temps);
	  strcpy(arh_dev,"/dev/");
	  strcat(arh_dev,temps);
	}
      fclose(in);
    }

  if(n > 1)printf("Multiple lirc devices found - check device connection\n");
  }



  if(n == 0)
  {
	  printf("No device found - check Arduino connection\n");
	  exit(0);
  }
}
//===============================
void readIpAddress(char *ips)
//===============================
{
  FILE  *in;
  char  line[128];
  char  temps[12];
  int   net = 0,netType=0;

  system("ifconfig > ipaddress.nab");
  delay(1000);
  in = fopen("ipaddress.nab","r");
  if(silent==0)printf("Open ip file\n");
  strcpy(ips,"no ip found");
  while (fgets(line,sizeof line,in) != NULL)
  { 
          if(strstr(line,"wlan") != NULL)
          {
             net = 1; //wlan
          }
          if(strstr(line,"eth") != NULL)
          {
             net = 2; //eth
          }
          if(strstr(line,"Loopback") != NULL)
          {
             net = 3; //lo
          }
          if(strstr(line,"inet addr:") != NULL)
          {
             if(net != 3)
             {
               netType = net;
               sscanf(line,"%s %s",temps,ips);
             }
          }
  }
  fclose(in);
  if(silent==0)printf("%d %s\n",netType,ips);
  return;
}
//===============================
int syncArduino()
//===============================
{
  unsigned char c='D';
  unsigned char z='D';
  int i,temp1,temp2;
  unsigned char inres[240],sync[8];     
  int nn = 0,sy = 0;
  
  
  while(sy == 0)
  {
    while (c != ';')
    {
      if (read(tty_fd,&c,1)>0) 
        {
          if(silent==0)printf("<%c>",c);
          inres[nn] = c;
          nn++;
        }
    }
    c = ' ';
    inres[nn-1] = '\0';
  
    if(silent==0)printf("SyncGWY: Received from Arduino: (%s) len=%d\n",inres,nn);
    sscanf(inres,"%s",sync);
    if(strstr(sync,"X") != NULL) sy = 1;
  }
  sendArduino(1,"Y");
  delay(1000);
  //serialFlush();
  return(0);
}
//===============================
void init()
//===============================
{
  char ip[80];
  int i;
  
 
  readConfig();
  readIpAddress(ip);
  readDeviceName();

  printf(NC_VERSION);
  printf("\nURL.......: %s\n",arh_url);
  printf(  "PAGE......: %s\n",arh_page);
  printf(  "Device....: %s\n",arh_dev);
  printf(  "IP........: %s\n",ip);

 
  //printf("ARDUINO CONNECTION\n");
  memset(&tio,0,sizeof(tio));
  tio.c_iflag=0;
  tio.c_oflag=0;
  tio.c_cflag=CS8|CREAD|CLOCAL;  // 8n1, see termios.h for more information
  tio.c_lflag=0;
  tio.c_cc[VMIN]=1;
  tio.c_cc[VTIME]=5;
  if((tty_fd = open(arh_dev , O_RDWR | O_NONBLOCK)) == -1)
  {
        if(silent==0)printf("GWY: Waiting for Arduino connection...\n"); 
  }
  else
  {
        if(silent==0)printf("GWY: Connected to Arduino %s\n",arh_dev); 
        cfsetospeed(&tio,BAUDRATE);    
        cfsetispeed(&tio,BAUDRATE);      
        tcsetattr(tty_fd,TCSANOW,&tio);
        tcsetattr(tty_fd, TCSAFLUSH, &tio);
  }            
      
  for(i=0;i<100;i++)on[i] = 0;
  delay(1000);
  g_count = 0;
  writeDebug();
  //if(silent==0)printf("GWY: Arduino sync ...\n"); 
  //syncArduino();
  //if(silent==0)printf("GWY:Arduino sync ok\n"); 
}
//===============================
void sendAckToArduino()
//===============================
{
	msg[0] = NABTON_DATA_ACK;
    msg[1] = (nb_sid&0xff);
    int itemp = nb_sid >> 8;
    msg[2] = (itemp&0xff);
    sendArduino(3,msg);
}
//===============================
int main(int argc, char **argv)
//===============================
{   
  int i,value = 9999, nc_state;
  time_t tm;
  struct tm *ltime;

  char res[120],stemp[120],sys[240];
    
  silent = 1;    
  if(argc == 2)
  {
    if(strstr(argv[1],"-d") != NULL) 
     silent = 0;
  }
  
 
  init(); 
  printf("a1\n"); 
  while(1)
  {
      int go = 0;
      printf("a2\n"); 
      go = recArduino();
      printf("a3\n"); 
      if(go == 1)
      {
         g_count++;
         writeDebug();
	 /*
         if(nb_nodata == 0 && nb_float == 1)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.1f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 2)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.2f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 3)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.3f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 4)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.4f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 5)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.5f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 6)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d&data=%.6f\"",arh_url,nb_sid,nb_data);
         if(nb_nodata == 1)sprintf(sys,"wget -q -O download.nab \"http://%s?sid=%d\"",arh_url,nb_sid);
         if(silent==0)printf("GWY: %s\n",sys);
         system(sys);
         * */
         printf("float %d\n",nb_float);
         if(nb_float < 1 || nb_float > 6)nb_float = 2;
         if(nb_nodata == 0 && nb_float == 1)sprintf(sys,"?sid=%d&data=%.1f",nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 2)sprintf(sys,"?sid=%d&data=%.2f",nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 3)sprintf(sys,"?sid=%d&data=%.3f",nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 4)sprintf(sys,"?sid=%d&data=%.4f",nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 5)sprintf(sys,"?sid=%d&data=%.5f",nb_sid,nb_data);
         if(nb_nodata == 0 && nb_float == 6)sprintf(sys,"?sid=%d&data=%.6f",nb_sid,nb_data);
         if(nb_nodata == 1)sprintf(sys,"?sid=%d\"",nb_sid);
  
         strcpy(stemp,arh_page);
         strcat(stemp,sys);
         if(silent==0)printf("GWY: %s\n",stemp);
         char* html = httpClient(arh_url,stemp);
         
         handleServerResponse(html);
      }

	  if(go == 2) // Unknown message
      {
		  if(silent==0)printf("GWY: Unknown message from Arduino\n");
		  sendAckToArduino();
	  }
	  
	  if(go == 3) // Error from Arduino
      {
		  if(silent==0)printf("GWY: Error message processed from Arduino\n");
		  sendAckToArduino();
	  }
	  if(go == 4) // Log from Arduino
      {
		  if(silent==0)printf("GWY: Log message processed from Arduino\n");
		  sendAckToArduino();
	  }
  }
           
  close(tty_fd);
  return EXIT_SUCCESS;
}
//===============================
char* httpClient(char* host, char* page)
//===============================
{
  struct sockaddr_in *remote;
  int sock;
  int tmpres;
  char *ip;
  char *get;
  char buf[BUFSIZ+1];

  //usage(host,page);
 
  sock = create_tcp_socket();
  ip = get_ip(host);
  //fprintf(stderr, "IP is %s\n", ip);
  remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
  remote->sin_family = AF_INET;
  tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
  if( tmpres < 0)  
  {
    perror("Can't set remote->sin_addr.s_addr");
    exit(1);
  }else if(tmpres == 0)
  {
    fprintf(stderr, "%s is not a valid IP address\n", ip);
    exit(1);
  }
  remote->sin_port = htons(PORT);
 
  if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
    perror("Could not connect");
    exit(1);
  }
  get = build_get_query(host, page);
  //fprintf(stderr, "Query is:\n<<START>>\n%s<<END>>\n", get);
 
  //Send the query to the server
  int sent = 0;
  while(sent < strlen(get))
  {
    tmpres = send(sock, get+sent, strlen(get)-sent, 0);
    if(tmpres == -1){
      perror("Can't send query");
      exit(1);
    }
    sent += tmpres;
  }
  //now it is time to receive the page
  memset(buf, 0, sizeof(buf));
  int htmlstart = 0;
  char * htmlcontent;
  while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0){
    if(htmlstart == 0)
    {
      /* Under certain conditions this will not work.
      * If the \r\n\r\n part is splitted into two messages
      * it will fail to detect the beginning of HTML content
      */
      htmlcontent = strstr(buf, "\r\n\r\n");
      if(htmlcontent != NULL){
        htmlstart = 1;
        htmlcontent += 4;
      }
    }else{
      htmlcontent = buf;
    }
    if(htmlstart){
      strcpy(g_buf,htmlcontent);
    }
 
    memset(buf, 0, tmpres);
  }
  if(tmpres < 0)
  {
    perror("Error receiving data");
  }
  free(get);
  free(remote);
  free(ip);
  close(sock);
  return g_buf;
}
//===============================
void usage(char* host, char* page)
//===============================
{
  fprintf(stderr, "USAGE: htmlget host=%s [page=%s]\n",host,page);
}
 
//=============================== 
int create_tcp_socket()
//===============================
{
  int sock;
  if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
    perror("Can't create TCP socket");
    exit(1);
  }
  return sock;
}
 
//=============================== 
char *get_ip(char *host)
//===============================
{
  struct hostent *hent;
  int iplen = 15; //XXX.XXX.XXX.XXX
  char *ip = (char *)malloc(iplen+1);
  memset(ip, 0, iplen+1);
  if((hent = gethostbyname(host)) == NULL)
  {
    printf("ip:%s\n",host);
    herror("Can't get IP");
    exit(1);
  }
  if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
  {
    perror("Can't resolve host");
    exit(1);
  }
  return ip;
}
 
char *build_get_query(char *host, char *page)
{
  char *query;
  char *getpage = page;
  char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
  if(getpage[0] == '/'){
    getpage = getpage + 1;
    fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
  }
  // -5 is to consider the %s %s %s in tpl and the ending \0
  query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(tpl)-5);
  sprintf(query, tpl, getpage, host, USERAGENT);
  return query;
}
//===============================
// End of file
//===============================

